package com.winning.pmph.utils;

import com.winning.pmph.entity.Tag;
import com.winning.pmph.service.TagService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringEscapeUtils;
import org.apache.commons.lang3.StringUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.nodes.Node;
import org.jsoup.select.Elements;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.*;

@Slf4j
public class Utils {
    private static TagService tagService = ApplicationContextUtil.getBean(TagService.class);
    public static String escapeXml10(String input) {
        return StringEscapeUtils.escapeXml10(input);
    }

    public static String unescapeXml(String input) {
        return StringEscapeUtils.unescapeXml(input);
    }

    public static String br2p(String input) {
        Document doc = Jsoup.parse(input);
        Elements ps = doc.getElementsByTag("p");
        for (Element p : ps) {
            String[] texts = p.html().split("<br\\s*/?\\s*>");
            if (texts.length > 1) {
                String html = "";
                for (int i = 0; i < texts.length; i++) {
                    String text = texts[i].trim();
                    if (text.length() > 0) {
                        html += "<p>" + texts[i].trim() + "</p>";
                    }
                }
                p.after(html);
                p.remove();
            } else {
                Elements brs = p.select("br");
                brs.remove();
            }
        }
        Elements as = doc.getElementsByTag("a");
        for (Element a : as) {
            a.unwrap();
        }
        return Jsoup.parse(doc.body().html()).body().html();
    }

    //根据图片尺寸大小识别类型
    public static String getImgType(String url) {
        BufferedImage sourceImg = null;
        try {
            if (url.startsWith("PICTUREURL/")) {
                InputStream murl = new URL("http://192.168.4.158:9989/?pic_path=./data" + url.substring(11)).openStream();
                sourceImg = ImageIO.read(murl);
            }
        } catch (IOException e) {
        }
        if (sourceImg == null) {
            System.out.println("【【发现未知图片】】" + url);
            return "default";
        }
        int h = sourceImg.getHeight();
        int w = sourceImg.getWidth();
        if (h <= 150 && w <= 200 && Math.abs(h - w) <= 6) {
            return "bz hnt";
        }
        if (h <= 150 && w <= 200) {
            return "default hnt";
        }
        return "default";
    }

    private static String getImgMainType(String classstr, String id) {
        if (StringUtils.containsIgnoreCase(classstr, "table")) return "table";
        if (StringUtils.containsIgnoreCase(classstr, "general")) return "general";
        if (StringUtils.containsIgnoreCase(classstr, "picture")) return "picture";
        if (StringUtils.containsIgnoreCase(classstr, "cover")) return "cover";
        if (StringUtils.containsIgnoreCase(classstr, "formula")) return "formula";
        if (StringUtils.containsIgnoreCase(classstr, "flow")) return "flow";
        if (StringUtils.containsIgnoreCase(classstr, "bz")) return "bz hnt";
        if (StringUtils.containsIgnoreCase(classstr, "other")) return "other";
        if (StringUtils.containsIgnoreCase(classstr, "CT")) return "picture";
        if (StringUtils.containsIgnoreCase(classstr, "GS")) return "formula";
        if (StringUtils.containsIgnoreCase(classstr, "HNT")) return "default hnt";
        if (id.matches("^P\\d+[-_]?.*")) return "default";
        if (id.matches("^T\\d+[-_]?.*")) return "table";

        return "default";
    }

    //处理平台产生的img行尾文字，追加换行。必须先进行行内图处理。处理img前后格式
    public static String imgAfter(String input) {
        Document doc = Jsoup.parse(input);
        Elements imgs = doc.body().getElementsByTag("img");
        Set<Element> ps = new HashSet<>();
        for (Element img : imgs) {
            String src = img.attr("src");
            if (StringUtils.isBlank(src)) {
                continue;
            }
            img.attr("src", src.replace("PICTUREURL", "http://192.168.4.158:9989/?pic_path=./data"));
            
            /*if (src.contains("booksPics")) {
                String type = getImgType(src);
                if (!img.hasClass("rw_img")) {
                    img.removeAttr("class");
                    img.addClass("rw_img " + type);
                }
                //处理平台产生img为补字图的情况，通过图片大小和尺寸判断
                if (!type.contains("hnt")) {
                    ps.add(img.parent());
                }
            }*/
        }
        /*for (Element parent : ps) {
            String html = "";
            String line = "";
            for (Node node : parent.childNodes()) {
                if (node.nodeName().equalsIgnoreCase("img")) {
                    String nodeclass = node.attr("class");
                    if (nodeclass.contains("hnt") && nodeclass.contains("rw_img")) {
                        line += node.outerHtml().trim();
                    } else {
                        if (!StringUtils.isBlank(line)) {
                            html += "<p>" + line + "</p>";
                        }
                        html += "<p>" + node.outerHtml() + "</p>";
                        line = "";
                    }
                } else {
                    if (node.nodeName().equalsIgnoreCase("p")) {
                        if (!StringUtils.isBlank(line)) {
                            html += "<p>" + line + "</p>";
                        }
                        html += node.outerHtml();
                        line = "";
                    } else {
                        line += node.outerHtml().trim();
                    }
                }
            }
            if (!StringUtils.isBlank(line)) {
                html += "<p>" + line + "</p>";
            }
            parent.after(html);
            parent.remove();
        }*/
        return Jsoup.parse(doc.body().html()).body().html();
    }

    public static String clearImgAttr(String input) {
        Document doc = Jsoup.parse(input);
        Elements imgs = doc.body().getElementsByTag("img");
        for (Element img : imgs) {
            String src = img.attr("src");
            if (StringUtils.isBlank(src)) {
                continue;
            }
            img.attr("src", src.replace("PICTUREURL", "http://192.168.4.158:9989/?pic_path=./data"));
            img.removeAttr("width");
            img.removeAttr("height");
            img.removeAttr("data-preview-src");
            img.removeAttr("data-preview-group");
            //img.attr("style","width: 50%;text-align: center;margin-left: -28px;");
        }
        return Jsoup.parse(doc.body().html()).body().html();
    }

    //识别表题并标记
    public static String tTitle(String input) {
        Document doc = Jsoup.parse(input);
        //[空格*]表[空格?]xxxx空格[题]
        Elements ps = doc.body().select("p:matches(^[ \\f\\n\\r\\t\\v　]*表[ \\f\\n\\r\\t\\v　]?[A-Za-z0-9_-]+[ \\f\\n\\r\\t\\v　]?)");
        ps.addAll(doc.body().select("p:matches(^续表$)"));
        ps.addAll(doc.body().select("p.t_title"));
        Set<Element> set = new LinkedHashSet<>(ps);
        for (Element p : set) {
            Element next = p.nextElementSibling();
            if (next == null) {
                continue;
            }
            if (next.childNodeSize() > 0 && next.childNode(0).nodeName().equalsIgnoreCase("img")) {
                Node img = next.childNode(0);
                String src = img.attr("src");
                if (StringUtils.startsWith(src, "data:image")) {
                    continue;
                }
                String name = FilenameUtils.removeExtension(new File(src).getName());
                //p.addClass("t_title");
                p.attr("style", "text-align: center; text-indent: 0px; font-size: 14px; color: #0f45ff;");
                p.attr("name", name);
            }
        }
        return Jsoup.parse(doc.body().html()).body().html();
    }

    //识别图题并标记
    public static String pTitle(String input) {
        Document doc = Jsoup.parse(input);
        //[空格*]图[空格?]xxxx空格[题]
        Elements ps = doc.body().select("p:matches(^[ \\f\\n\\r\\t\\v　]*图[ \\f\\n\\r\\t\\v　]?[A-Za-z0-9_-]+[ \\f\\n\\r\\t\\v　]?)");
        ps.addAll(doc.body().select("p.p_title"));
        Set<Element> set = new LinkedHashSet<>(ps);
        for (Element p : set) {
            Element previous = p.previousElementSibling();
            if (previous == null) {
                continue;
            }
            if (previous.childNodeSize() > 0 && previous.childNode(0).nodeName().equalsIgnoreCase("img")) {
                Node img = previous.childNode(0);
                String src = img.attr("src");
                if (StringUtils.startsWith(src, "data:image")) {
                    continue;
                }
                String name = FilenameUtils.removeExtension(new File(src).getName());
                //p.addClass("p_title");
                p.attr("style", "text-align: center; text-indent: 0px; font-size: 14px; color: #0f45ff;");
                p.attr("name", name);
            }
        }
        return Jsoup.parse(doc.body().html()).body().html();
    }

    private static Element searchPrevious(Element current) {
        Element previous = current.previousElementSibling();
        if (previous == null) {
            return null;
        }
        if (previous.childNodeSize() > 0 && previous.childNode(0).nodeName().equalsIgnoreCase("img") && !previous.childNode(0).nodeName().contains("hnt")) {
            return previous.child(0);
        } else if (previous.tagName().equalsIgnoreCase("p") && previous.className().contains("title")) {
            return previous;
        }
        return searchPrevious(previous);
    }

    public static String note(String input) {
        Document doc = Jsoup.parse(input);
        //[空格*]注[:|：]
        Elements ps = doc.body().select("p:matches(^[ \\f\\n\\r\\t\\v　]*注[：: \\f\\n\\r\\t\\v　])");
        ps.addAll(doc.body().select("p.p_note"));
        ps.addAll(doc.body().select("p.t_note"));
        Set<Element> set = new LinkedHashSet<>(ps);
        for (Element p : set) {
            Element previous = searchPrevious(p);
            if (previous == null) {
                continue;
            }
            if (previous.tagName().equalsIgnoreCase("img")) {
                String src = previous.attr("src");
                if (StringUtils.startsWith(src, "data:image")) {
                    continue;
                }
                String name = FilenameUtils.removeExtension(new File(src).getName());
                p.attr("name", name);
                if (previous.className().contains("table")) {
                    //p.addClass("t_note");
                    p.attr("style", "text-indent: 0px; font-size: 10px; color: #8018ff;");
                } else if (previous.className().contains("rw_img") && !previous.className().contains("hnt")) {
                    p.addClass("p_note");
                }
            } else if (previous.tagName().equalsIgnoreCase("p") && previous.className().contains("p_title")) {
                p.addClass("p_note");
                p.attr("name", previous.attr("name"));
            }
        }
        return Jsoup.parse(doc.body().html()).body().html();
    }

    //识别判断img类型并修改class
    public static String imgType(String input) {
        Document doc = Jsoup.parse(input);
        Elements imgs = doc.body().getElementsByTag("img");
        for (Element img : imgs) {
            String type = getImgMainType(img.className(), img.id());
            if (!img.classNames().contains("rw_img")) {
                img.removeAttr("class");
                img.addClass("rw_img " + type);
            }
            if (StringUtils.containsIgnoreCase(type, "default")) {
                String src = img.attr("src");
                String name = FilenameUtils.removeExtension(new File(src).getName());
                Elements ps = doc.body().select("[name=" + name + "]");
//                img.removeAttr("class");
                for (Element p : ps) {
                    if (p.classNames().contains("t_title")) {
                        //有表题的
                        img.removeClass("default");
                        img.addClass("table");
                    }
                    if (p.classNames().contains("p_title")) {
                        //有图题的
                        img.removeClass("default");
                        String text = p.text();
                        if (StringUtils.contains(text, "示意图")) {
                            img.addClass("general");
                        } else if (StringUtils.contains(text, "公式")) {
                            img.addClass("formula");
                        } else if (StringUtils.contains(text, "流程")) {
                            img.addClass("flow");
                        } else {
                            img.addClass("default");
                        }
                    }
                }
            }
            // 图片p标记class
            if (!StringUtils.containsIgnoreCase(type, "hnt")) {
                if (StringUtils.containsIgnoreCase(type, "table")) {
                    img.parent().addClass("table");
                } else {
                    img.parent().addClass("picture");
                }
            }
        }
        return Jsoup.parse(doc.body().html()).body().html();
    }

    //img设置ID
    public static String addImgId(String input) {
        Document doc = Jsoup.parse(input);
        Elements imgs = doc.body().getElementsByTag("img");
        for (Element img : imgs) {
            String src = img.attr("src");
            if (StringUtils.startsWith(src, "data:image")) {
                System.out.println("*** BASE64 IMG ***");
                continue;
            }
            String name = FilenameUtils.removeExtension(new File(src).getName());
            String type = getImgMainType(img.className(), img.id());
            img.attr("id", type + "_" + name);
        }
        return Jsoup.parse(doc.body().html()).body().html();
    }

    public static String clearoffice(String input) {
        //删除注释
        input = input.replaceAll("(?s)<\\!\\-\\-.+?\\-\\->", "");
        Document doc = Jsoup.parse(input);
        Elements ops = doc.body().select("o|p");
        ops.remove();
        Elements mso = doc.body().select(".MsoNormal");
        mso.removeClass("MsoNormal");
        return Jsoup.parse(doc.body().html()).body().html();
    }

    public static String addGroup(String input) {
        Document doc = Jsoup.parse(input);
        Elements imgs = doc.body().getElementsByTag("img");
        Set<Element> ps = new HashSet<>();
        for (Element img : imgs) {
            if (!img.className().contains("hnt")) {
                ps.add(img.parent());
            }
        }
        for (Element p : ps) {
            if (p.parent().tagName().equalsIgnoreCase("div") && p.parent().className().contains("rw_img")) {
                continue;
            }
            //todo
        }
        return Jsoup.parse(doc.body().html()).body().html();
    }

    public static String format(String input, String md5) {
        Document doc = Jsoup.parse(input);
        for (int i = 0; i < doc.body().childNodeSize(); ) {
            Node child = doc.body().childNode(i);
            if (child instanceof Element) {
                Element element = (Element) child;
                if (element.tagName().equalsIgnoreCase("p")) {
                    if (StringUtils.isBlank(element.html())) {
                        child.remove();
                        continue;
                    }
                } else if (element.tagName().equalsIgnoreCase("img")) {
                    element.wrap("<p></p>");
                } else if (element.tagName().equalsIgnoreCase("div")) {
                    element.unwrap();
                } else if (element.tagName().equalsIgnoreCase("br")) {
                    element.remove();
                } else {
                    System.out.println("【【发现未知元素】】" + element.outerHtml());
                }
            }
            if (child.nodeName().equals("#text")) {
                if (StringUtils.isBlank(child.outerHtml())) {
                    child.remove();
                    continue;
                }
                child.wrap("<p></p>");
            }
            i++;
        }
        String output = doc.body().html();
        String md5_ = DigestUtils.md5Hex(output);
        if (md5_.equalsIgnoreCase(md5)) {
            return output;
        }
        return format(output, md5_);
    }

    public static String clearFormat(String input) {
        if (StringUtils.isBlank(input)) {
            return input;
        }
        input = input.replaceAll("&nbsp;", " ").trim();
        input = Utils.clearoffice(input);
        input = Utils.format(input, "");
        input = Utils.br2p(input);
        input = Utils.clearImgAttr(input);
        /*input = Utils.imgAfter(input);
        input = Utils.clearImgAttr(input);
        input = Utils.tTitle(input);
        input = Utils.pTitle(input);
        input = Utils.imgType(input);
        input = Utils.note(input);*/
        input = Utils.format(input, "");
        return input;
    }

    /**
     * 通过一级标签分类名称来获取二级以及一下的标签分类的集联列表
     *
     * @param tagName 一级标签分类名称
     * @return 二级以及一下的标签分类的集联列表
     */
    public static List<Map<String, Object>> getTagCascade(String tagName) {
        log.debug("getTagCascade called");
        String sql = "with recursive children_tag as (\n" +
                "    select * from tag where tag.NAME = '" + tagName + "'\n" +
                "    union all\n" +
                "    select t.* from tag t inner join children_tag ct on ct.ID = t.PARENT_ID\n" +
                ") select * from children_tag";
        log.debug("sql: " + sql);
        List<Tag> tagList = tagService.getBaseMapper().executeMultiSelect(sql);
        if (tagList.size() == 0) {
            return new ArrayList<>();
        }
        String rootId = tagList.get(0).getId();
        log.debug("rootId: " + rootId);

        Map<String, List<Tag>> tagListMap = new HashMap<>();
        for (Tag tag : tagList) {
            if (tagListMap.containsKey(tag.getParentId())) {
                List<Tag> tempList = tagListMap.get(tag.getParentId());
                tempList.add(tag);
            } else {
                List<Tag> tempList = new ArrayList<>();
                tempList.add(tag);
                tagListMap.put(tag.getParentId(), tempList);
            }
        }

        List<Map<String, Object>> tagCascadeList = getChildTagCascadeList(rootId, tagListMap);
        log.debug("getTagCascade return");
        return tagCascadeList;
    }



    private static List<Map<String, Object>> getChildTagCascadeList(String rootId, Map<String, List<Tag>> tagListMap) {
        log.debug("getChildTagCascadeList called");
        List<Map<String, Object>> tagCascadeList = new ArrayList<>();
        List<Tag> childTagList = tagListMap.get(rootId);
        if (childTagList != null) {
            for (Tag tag : childTagList) {
                Map<String, Object> tagCascadeMap = new HashMap<>();
                tagCascadeMap.put("value", tag.getId());
                tagCascadeMap.put("label", tag.getName());
                List<Map<String, Object>> childList = getChildTagCascadeList(tag.getId(), tagListMap);
                if (childList.size() > 0) {
                    tagCascadeMap.put("children", childList);
                }
                tagCascadeList.add(tagCascadeMap);
            }
        }
        log.debug("getChildTagCascadeList return");
        return tagCascadeList;
    }

    public static List<Map<String, Object>> getTagCascadeId(String id) {
        log.debug("getTagCascade called");
        String sql = "with recursive children_tag as (\n" +
                "    select * from tag where id = '" + id + "'\n" +
                "    union all\n" +
                "    select t.* from tag t inner join children_tag ct on ct.ID = t.PARENT_ID\n" +
                ") select * from children_tag";
        log.debug("sql: " + sql);
        List<Tag> tags = tagService.getBaseMapper().executeMultiSelect(sql);
        if (tags.size() == 0) {
            return new ArrayList<>();
        }
        String rootId = tags.get(0).getId();
        log.debug("rootId: " + rootId);

        Map<String, List<Tag>> tagListMap = new HashMap<>();
        for (Tag tag : tags) {
            if (tagListMap.containsKey(tag.getParentId())) {
                List<Tag> tempList = tagListMap.get(tag.getParentId());
                tempList.add(tag);
            } else {
                List<Tag> tempList = new ArrayList<>();
                tempList.add(tag);
                tagListMap.put(tag.getParentId(), tempList);
            }
        }

        List<Map<String, Object>> tagCascadeList = getChildTagCascadeList(rootId, tagListMap);
        log.debug("getTagCascade return");
        return tagCascadeList;
    }
}
